import { useEffect, useContext, useState, createRef } from 'react';
import { useRequest, usePrevious } from '@umijs/hooks';
import Graphin, { Behaviors, GraphinContext, G6 } from '@antv/graphin';
import { ContextMenu } from '@antv/graphin-components';
import { Algorithm } from '@antv/g6';
import iconLoader from '@antv/graphin-icons';
import '@antv/graphin-icons/dist/index.css';
import { message, Spin } from 'antd';
import { OptionToolbarTwo } from '@/components/Toolbar';

import {
  getControlPath,
  getControlNetwork,
  getCapitalName,
  getCapitalNetwork,
} from '@/services/zhirong/controlPower';

import style from '../style.less';

const { fontFamily } = iconLoader();
const icons = Graphin.registerFontFamily(iconLoader);
const { Menu } = ContextMenu;

const { louvain, labelPropagation } = Algorithm;
const { uniqueId } = G6.Util;
const { DragNodeWithForce, ActivateRelations } = Behaviors;

const EDGE_HIGHLIGHT_KEYSHAPE = {
  fill: 'red',
  stroke: 'red',
  lineWidth: 2,
};
const EDGE_NORMAL_KEYSHAPE = {
  fill: '#999',
  stroke: '#999',
  lineWidth: 1,
};

const dataProcess = (data, enterprise) => {
  const { nodes, links, related_nodes } = data;
  const ids = nodes.map((node) => node.id);
  nodes.forEach((node) => {
    node.style = {
      icon: {
        fontFamily,
        type: 'font',
        value: node.category === 'E' ? icons.company : icons.user,
        fill: node.id === enterprise.eid ? 'red' : '#1890ff',
        size: 25,
        fillOpacity: 0.8,
        // value: icons.home
      },
      keyshape: {
        size: node.id === enterprise.eid ? 45 : 40,
        fill: node.id === enterprise.eid ? 'red' : '#1890ff',
        stroke: node.id === enterprise.eid ? 'red' : '#1890ff',
        fillOpacity: 0.2,
      },
      label: {
        value: node.name,
      },
    };
    node.label = node.name;
  });

  const edges = [];
  links.forEach((e) => {
    e.forEach((link) => {
      link.style = {
        keyshape: {
          fill: '#999',
          stroke: '#999',
          lineWidth: 1,
        },
        label: {
          value: `控制${(link.value * 100).toFixed(2)}%`,
          fill: '#f00',
        },
      };
      edges.push(link);
    });
  });
  related_nodes.forEach((node) => {
    if (!ids.includes(node.id) && edges.some((e) => e.source === node.id || e.target === node.id)) {
      nodes.push({
        ...node,
      });
      ids.push(node.id);
    }
  });
  return { nodes, edges };
};
// 路径高亮
const HighlightPath = (props) => {
  const { graph, apis } = useContext(GraphinContext);
  const previousHighlight = usePrevious(props.hightlightConfig);
  useEffect(() => {
    handleHighlight(previousHighlight, props.hightlightConfig);
    // console.log(graph)
  }, [props.hightlightConfig]);

  const handleHighlight = (previousConfig, config) => {
    const preEdges = previousConfig ? previousConfig.edges : [];
    const curEdges = config.edges;
    preEdges.forEach((item) => {
      const edge = graph.find('edge', (edge) => {
        return edge.getModel().source === item.source && edge.getModel().target === item.target;
      });
      try {
        const model = edge.getModel();
        const { style } = model;
        graph.updateItem(edge, {
          ...model,
          style: {
            ...style,
            keyshape: EDGE_NORMAL_KEYSHAPE,
          },
        });
      } catch (error) {
        console.log(
          "Find error in handleHighlight, while changing preEdges' style, details:",
          error,
        );
      }
    });
    curEdges.forEach((item) => {
      const edge = graph.find('edge', (edge) => {
        return edge.getModel().source === item.source && edge.getModel().target === item.target;
      });
      try {
        const model = edge.getModel();
        const { style } = model;
        graph.updateItem(edge, {
          ...model,
          style: {
            ...style,
            keyshape: EDGE_HIGHLIGHT_KEYSHAPE,
          },
        });
      } catch (error) {
        console.log(
          "Find error in handleHighlight, while changing curEdges' style, details:",
          error,
        );
      }
    });
  };

  return null;
};

// 控制关联路径
const ControlPathGraph = (props) => {
  const [enterprises, setEnterprises] = useState(props.enterprises);
  // const { graph, apis } = useContext(GraphinContext)
  // const graphinRef = createRef()
  // useEffect(() => {
  //     const { graph, apis } = graphinRef.current
  //     console.log(graph)
  // }, [])
  const [network, setNetwork] = useState({
    nodes: [
      {
        name: 'test',
        id: 'test',
      },
    ],
    edges: [],
    combo: undefined,
  });

  useEffect(() => {
    if (network.nodes.length === 1 && network.nodes[0].name === 'test') {
      setIsDisplay({ ...isDisplay, cover: true, graph: false });
    } else {
      setIsDisplay({ ...isDisplay, graph: true, cover: false });
    }
  }, [network]);

  const { loading, run } = useRequest(getControlPath, {
    manual: true,
    onSuccess: (result, params) => {
      if (result.code === 0) {
        dataProcess(result.data);
        updateControlPath(result.data);
      } else if (result.code === 666) {
        message.info('查询的实体间不存在控制路径.');
      } else {
        message.error('获取查询结果失败！');
      }
    },
    onError: (e, params) => {
      console.log('Error detail: ', e);
      console.log('params: ', params);
      message.error('数据请求错误！');
    },
  });

  useEffect(() => {
    console.log(enterprises);
    if (enterprises.enterpriseA && enterprises.enterpriseB) {
      const { enterpriseA, enterpriseB } = enterprises;
      if (enterpriseA.eid && enterpriseB.eid) {
        run({
          entityA: enterpriseA.eid,
          entityB: enterpriseB.eid,
          direction: 1,
          dateFrom: '2018-01-01',
          dateTo: '2018-12-31',
          ts: new Date().getTime(),
        });
      }
    }
  }, [enterprises]);

  useEffect(() => {
    setEnterprises(props.enterprises);
  }, [props.enterprises]);

  useEffect(() => {
    props.onLoadingStateChange(loading);
    console.log('loading state change to :', loading);
    setIsDisplay({ ...isDisplay, shadow: loading && !isDisplay.cover });
  }, [loading]);

  const [isDisplay, setIsDisplay] = useState({
    cover: true,
    graph: false,
    shadow: false,
  });

  // const previousHighlight = usePrevious(props.hightlightConfig)
  // useEffect(() => {
  //     handleHighlight(previousHighlight, props.hightlightConfig)
  // }, [props.hightlightConfig])

  const dataProcess = (data) => {
    // let nodeSet = new Set(), linkSet = new Set()
    let linkSet = new Set();
    data.pathList.forEach((path) => {
      let { links } = path;
      // nodes.forEach(node => {
      //     nodeSet.add(JSON.stringify(node))
      // })
      links.forEach((link) => {
        linkSet.add(JSON.stringify(link));
      });
    });
    // let nodeArray = Array.from(nodeSet)
    let nodeArray = data.nodes;
    let linkArray = Array.from(linkSet);
    nodeArray = nodeArray.map((node) => {
      node = JSON.parse(node);
      node.style = {
        icon: {
          fontFamily,
          type: 'font',
          value: node.category === 'E' ? icons.company : icons.user,
          fill:
            node.id === enterprises.enterpriseA.eid || node.id === enterprises.enterpriseB.eid
              ? 'red'
              : '#1890ff',
          size: 25,
          fillOpacity: 0.8,
          // value: icons.home
        },
        keyshape: {
          size:
            node.id === enterprises.enterpriseA.eid || node.id === enterprises.enterpriseB.eid
              ? 45
              : 40,
          fill:
            node.id === enterprises.enterpriseA.eid || node.id === enterprises.enterpriseB.eid
              ? 'red'
              : '#1890ff',
          stroke:
            node.id === enterprises.enterpriseA.eid || node.id === enterprises.enterpriseB.eid
              ? 'red'
              : '#1890ff',
          fillOpacity: 0.2,
        },
        label: {
          value: node.name,
        },
      };
      node.label = node.name;
      return node;
    });
    linkArray = linkArray.map((edge) => {
      edge = JSON.parse(edge);
      edge.style = {
        keyshape: {
          fill: '#999',
          stroke: '#999',
          lineWidth: 1,
        },
        label: {
          value: `控制${(edge.value * 100).toFixed(2)}%`,
          fill: '#f00',
        },
      };
      return edge;
    });
    // console.log(nodeArray, linkArray)
    setNetwork({ ...network, nodes: nodeArray, edges: linkArray }); // setNetwork在这里可能是异步执行的？
    // console.log("dataProcess network: ", network) //更改之后的network并不能在这里log出来，所以这里log的结果还是[]
  };

  const updateControlPath = (data) => {
    let controllingParty = enterprises.enterpriseA.eid;
    let controlledParty = enterprises.enterpriseB.eid;
    let { totalControlPower: controlPower, pathList: controllPathList } = data;
    controllPathList.forEach((item, index) => {
      item.name = '控制路径' + (index + 1);
    });
    console.log(controllPathList);
    props.onUpdateNetwork({
      controllingParty,
      controlledParty,
      controlPower,
      controllPathList,
    });
  };

  const layout = {
    // type: 'gForce',
    type: 'dagre',
    rankdir: 'LR',
    // minMovement: 0.01,
    // maxIteration: 5000,
    // preventOverlap: true,
    // damping: 0.99,
  };
  return (
    <>
      {
        <div className={style.graphWrapper}>
          <Graphin data={network} layout={layout} style={{ opacity: isDisplay.graph ? 1 : 0 }}>
            <HighlightPath hightlightConfig={props.hightlightConfig} />
            <Spin spinning={loading}>
              <div id="shadow" style={{ display: isDisplay.shadow ? 'block' : 'none' }}></div>
              <img
                id="cover"
                src="/graph_cover.png"
                style={{ display: isDisplay.cover ? 'block' : 'none' }}
              />
            </Spin>
          </Graphin>
        </div>
      }
    </>
  );
};

// 控制权所属网络
const ControlledNetworkGraph = ({ enterprise }) => {
  const [network, setNetwork] = useState({
    nodes: [],
    edges: [],
    combo: undefined,
  });

  const { loading, run } = useRequest(getControlNetwork, {
    manual: true,
    onSuccess: (result) => {
      console.log("控制权", result);
      console.log(result);
      if (result.code === 0) {
        setNetwork(dataProcess(result.data, enterprise));
      } else if (result.code === 666) {
        message.info('查询的实体间不存在控制权所属网络.');
      } else {
        message.error('获取查询结果失败！');
      }
    },
    onError: () => {
      message.error('数据请求错误！');
    },
  });

  useEffect(() => {
    if (enterprise && enterprise.eid) {
      run({
        centerId: enterprise.eid,
        level: 2,
        direction: 1,
        dateFrom: '2018-01-01',
        dateTo: '2018-12-31',
        ts: new Date().getTime(),
      });
    }
  }, [enterprise]);

  const layout = {
    type: 'dagre',
    rankdir: 'BT',
    minMovement: 0.01,
    maxIteration: 5000,
    preventOverlap: true,
    damping: 0.99,
  };

  return (
    <div style={{ position: 'relative', width: '90vw' }}>
      <Graphin data={network} layout={layout} fitview fitcenter>
        <Spin spinning={loading}></Spin>
      </Graphin>
    </div>
  );
};

// 控制权网络
const ControlNetworkGraph = ({ enterprise }) => {
  const [network, setNetwork] = useState({
    nodes: [],
    edges: [],
    combo: undefined,
  });

  const { loading, run } = useRequest(getControlNetwork, {
    manual: true,
    onSuccess: (result) => {
      if (result.code === 0) {
        setNetwork(dataProcess(result.data, enterprise));
      } else if (result.code === 666) {
        message.info('查询的实体不存在控制权网络.');
      } else {
        message.error('获取查询结果失败！');
      }
    },
    onError: () => {
      message.error('数据请求错误！');
    },
  });

  useEffect(() => {
    if (enterprise && enterprise.eid) {
      run({
        centerId: enterprise.eid,
        level: 2,
        direction: 0,
        dateFrom: '2018-01-01',
        dateTo: '2018-12-31',
        ts: new Date().getTime(),
      });
    }
  }, [enterprise]);
  const layout = {
    type: 'gForce',
    minMovement: 0.01,
    maxIteration: 5000,
    preventOverlap: true,
    damping: 0.99,
  };

  return (
    <div style={{ position: 'relative' }}>
      {
        <Graphin data={network} layout={layout}>
          <Spin spinning={loading}></Spin>
        </Graphin>
      }
    </div>
  );
};

// 资本系网络
const CapitalNetworkGraph = (props) => {
  const graphinRef = createRef();

  const [enterprise, setEnterprise] = useState(props.enterprise);

  const [capitalNetwork, setCapitalNetwork] = useState({
    capitalName: '',
    capitalNetwork: {},
  });

  useEffect(() => {
    props.onUpdateNetwork(capitalNetwork);
  }, [capitalNetwork]);

  const [graphState, setGraphState] = useState({
    nodeMap: {},
    aggregatedNodeMap: {},
    network: {
      nodes: [
        {
          id: 'test',
          name: 'test',
        },
      ],
      edges: [],
    },
    originData: {},
    clusteredData: {},
    expandArray: [],
    collapseArray: [],
  });
  const { loading: loadingGetCapitalName, run: runGetCapitalName } = useRequest(getCapitalName, {
    manual: true,
    onSuccess: (result, params) => {
      if (result.code === 0) {
        try {
          const capitalName = result.data.capitalName;
          setCapitalNetwork({
            ...capitalNetwork,
            capitalName,
          });
          // console.log(capitalName)
          if (capitalName) {
            runGetCapitalNetwork({
              capitalName,
              date: '2018-01-01',
              ts: new Date().getTime(),
            });
          }
        } catch (error) {
          console.log('Error detail: ', error);
        }
      } else if (result.code === 666) {
        message.info('未找到该实体所属资本系.');
      } else {
        message.error('查询实体所属资本系名称失败！');
      }
    },
    onError: (e, params) => {
      console.log('Error detail: ', e);
      console.log('params: ', params);
      message.error('数据请求错误！');
    },
  });

  const { loading: loadingGetCapitalNetwork, run: runGetCapitalNetwork } = useRequest(
    getCapitalNetwork,
    {
      manual: true,
      onSuccess: (result, params) => {
        if (result.code === 0) {
          dataProcess(result.data);
        } else if (result.code === 666) {
          message.info('所查询的资本系中无数据.');
        } else {
          message.error('获取资本系数据失败！');
        }
      },
      onError: (e, params) => {
        console.log('Error detail: ', e);
        console.log('params: ', params);
        message.error('数据请求错误！');
      },
    },
  );

  useEffect(() => {
    if (graphState.network.nodes.length > 0) {
      const {
        graph, // g6 的Graph实例
        apis, // Graphin 提供的API接口
      } = graphinRef.current;
      console.log('Enter CapitalNetworkGraph page, ref:', graph, apis);
    }
    return () => {
      console.log('Quit CapitalNetworkGraph page.');
    };
  }, []);

  useEffect(() => {
    console.log(enterprise);
    if (enterprise && enterprise.eid) {
      runGetCapitalName({
        id: enterprise.eid,
        date: '2018-01-01',
        ts: new Date().getTime(),
      });
    }
  }, [enterprise]);

  useEffect(() => {
    setEnterprise(props.enterprise);
  }, [props.enterprise]);

  const dataProcess = (data) => {
    let { nodes, links } = data;
    nodes.forEach((node) => {
      node.style = {
        icon: {
          fontFamily,
          type: 'font',
          value: node.category === 'E' ? icons.company : icons.user,
          fill: node.name === enterprise.name ? 'red' : '#1890ff',
          size: 25,
          fillOpacity: 0.8,
          // value: icons.home
        },
        keyshape: {
          size: node.name === enterprise.name ? 45 : 40,
          fill: node.name === enterprise.name ? 'red' : '#1890ff',
          stroke: node.name === enterprise.name ? 'red' : '#1890ff',
          fillOpacity: 0.2,
        },
        label: {
          value: node.name,
        },
      };
      node.label = node.name;
    });
    links.forEach((edge) => {
      edge.style = {
        keyshape: {
          fill: '#999',
          stroke: '#999',
          lineWidth: 1,
        },
        label: {
          value: `控制${edge.value}%`,
          fill: '#f00',
        },
      };
    });

    // let clusterResult = louvain({nodes, edges: links}, true)
    let clusterResult = labelPropagation({ nodes, edges: links }, true);
    let collapseArray = [],
      aggregatedNodeMap = {},
      nodeMap = {};
    clusterResult.clusters.forEach((node) => {
      node.count = node.nodes.length;
      collapseArray.push(node.id);
      node.nodes.forEach((item) => {
        item.clusterId = node.id;
        nodeMap[item.id] = item;
        if (item.name === enterprise.name) {
          node.isContainQueryEnterprise = true;
        }
      });
      node.style = {
        keyshape: {
          size: 40 + node.count / 2,
          fill: node.isContainQueryEnterprise ? 'red' : undefined,
          stroke: node.isContainQueryEnterprise ? 'red' : undefined,
        },
        label: {
          value: node.count,
          position: 'center',
          offset: [0, 9],
        },
      };
      aggregatedNodeMap[node.id] = node;
    });

    const network = { nodes: clusterResult.clusters, edges: clusterResult.clusterEdges };
    setGraphState({
      ...graphState,
      network,
      aggregatedNodeMap,
      nodeMap,
      collapseArray,
      clusteredData: clusterResult,
      originData: { nodes, edges: links },
    });
    setCapitalNetwork({ ...capitalNetwork, capitalNetwork: { nodes, edges: links } });
    console.log('Capital network cluster result: ', clusterResult);
    // setNetwork({ nodes: clusterResult.clusters, edges: clusterResult.clusterEdges })
    // setNetwork({...network, nodes, edges: links }) // setNetwork在这里可能是异步执行的？
  };

  const layoutConfig = {
    type: 'graphin-force',
    minMovement: 0.01,
    maxIteration: 5000,
    preventOverlap: true,
    damping: 0.99,
  };
  // 清除图上所有focus状态及相应样式
  const clearFocusItemState = (graph) => {
    if (!graph) return;
    clearFocusNodeState(graph);
    clearFocusEdgeState(graph);
  };

  // 清除图上所有节点的 focus 状态及相应样式
  const clearFocusNodeState = (graph) => {
    const focusNodes = graph.findAllByState('node', 'focus');
    focusNodes.forEach((fnode) => {
      graph.setItemState(fnode, 'focus', false); // false
    });
  };

  // 清除图上所有边的 focus 状态及相应样式
  const clearFocusEdgeState = (graph) => {
    const focusEdges = graph.findAllByState('edge', 'focus');
    focusEdges.forEach((fedge) => {
      graph.setItemState(fedge, 'focus', false);
    });
  };

  const NodeMenu = () => {
    const { graph, contextmenu, layout, apis } = useContext(GraphinContext);
    const context = contextmenu.node;
    let manipulatePosition = {},
      cachePositions = {};
    const options = [
      {
        key: 'expand',
        name: '扩散',
      },
      {
        key: 'cluster',
        name: '聚合',
      },
      {
        key: 'tag',
        name: '打标',
      },
    ];
    const handleChange = (menuItem, menuData) => {
      switch (menuItem.key) {
        case 'expand':
          handleExpand(menuData);
          // layout.forceSimulation.restart(graph)
          // console.log(menuData)
          break;
        case 'cluster':
          handleCollapse(menuData);
          break;
        default:
          handleTag(menuData.id);
          break;
      }
    };

    const handleExpand = (model) => {
      const id = model.id;
      manipulatePosition = { x: model.x, y: model.y };
      const currentNodes = graph.getNodes();
      cachePositions = cacheNodePosition(currentNodes);
      if (graphState.aggregatedNodeMap[id]) {
        let expandArray = graphState.expandArray,
          collapseArray = graphState.collapseArray;
        const clusterIndex = collapseArray.findIndex((item) => item === id);
        if (clusterIndex === -1) {
          console.log('Error, can not find the id in collapse array');
          return;
        }
        expandArray.push(id);
        collapseArray =
          clusterIndex === 0
            ? collapseArray.slice(1)
            : collapseArray.slice(0, clusterIndex).concat(collapseArray.slice(clusterIndex + 1));
        const network = getGraphStateNetwork(expandArray, collapseArray);
        handleRefreshGraph(network);
        // console.log('get graph state network: ', network)
        setGraphState({ ...graphState, expandArray, collapseArray, network });
      }
      message.info(`展开聚类结点.`);
      // console.log(id)
      context.handleClose();
    };

    const handleCollapse = (model) => {
      const id = model.clusterId; // 该节点所属的cluster 的id
      manipulatePosition = { x: model.x, y: model.y };
      const currentNodes = graph.getNodes();
      cachePositions = cacheNodePosition(currentNodes);
      if (graphState.aggregatedNodeMap[id]) {
        let expandArray = graphState.expandArray,
          collapseArray = graphState.collapseArray;
        const clusterIndex = expandArray.findIndex((item) => item === id);
        if (clusterIndex === -1) {
          console.log('error, can not find the id in expand array');
          return;
        }
        collapseArray.push(id);
        expandArray =
          clusterIndex === 0
            ? expandArray.slice(1)
            : expandArray.slice(0, clusterIndex).concat(expandArray.slice(clusterIndex + 1));
        const network = getGraphStateNetwork(expandArray, collapseArray);
        handleRefreshGraph(network);
        console.log('get graph state network: ', network);
        setGraphState({ ...graphState, expandArray, collapseArray, network });
      }
      message.info(`收起该结点所属聚类.`);
      // console.log(model)
      context.handleClose();
    };

    const handleTag = (id) => {
      // message.info(`打标成功`)
      console.log(id);
      context.handleClose();
    };

    //根据展开的cluster列表和折叠的cluster列表生成graph上面要显示的nodes和edges
    const getGraphStateNetwork = (expandArray, collapseArray) => {
      let nodes = [],
        edges = [],
        expandMap = {},
        collapseMap = {};
      collapseArray.forEach((clusterId) => {
        collapseMap[clusterId] = true;
      });
      expandArray.forEach((clusterId) => {
        expandMap[clusterId] = true;
      });

      graphState.clusteredData.clusters.forEach((cluster) => {
        if (expandMap[cluster.id]) {
          nodes = nodes.concat(cluster.nodes);
        } else {
          nodes.push(graphState.aggregatedNodeMap[cluster.id]);
        }
      });
      console.log('expandMap', expandMap);
      graphState.originData.edges.forEach((edge) => {
        const isSourceInExpandArray = expandMap[graphState.nodeMap[edge.source].clusterId];
        const isTargetInExpandArray = expandMap[graphState.nodeMap[edge.target].clusterId];

        if (isSourceInExpandArray && isTargetInExpandArray) {
          edges.push(edge);
        } else if (isSourceInExpandArray) {
          const targetClusterId = graphState.nodeMap[edge.target].clusterId;
          const vedge = {
            source: edge.source,
            target: targetClusterId,
            id: uniqueId('edge'),
            label: '',
          };
          edges.push(vedge);
        } else if (isTargetInExpandArray) {
          const sourceClusterId = graphState.nodeMap[edge.source].clusterId;
          const vedge = {
            target: edge.target,
            source: sourceClusterId,
            id: uniqueId('edge'),
            label: '',
          };
          edges.push(vedge);
        }
      });

      graphState.clusteredData.clusterEdges.forEach((edge) => {
        if (expandMap[edge.source] || expandMap[edge.target]) return;
        else edges.push(edge);
      });
      return { nodes, edges };
    };
    //缓存当前图中结点位置坐标，新结点加入时，只为新节点初始化坐标
    const cacheNodePosition = (nodes) => {
      const positionMap = {};
      const nodeLength = nodes.length;
      for (let i = 0; i < nodeLength; i++) {
        const node = nodes[i].getModel();
        positionMap[node.id] = {
          x: node.x,
          y: node.y,
          level: node.level,
        };
      }
      return positionMap;
    };

    const handleRefreshGraph = (graphData, isNewGraph = false) => {
      if (!graphData || !graph) return;
      clearFocusItemState(graph);
      // reset the filtering
      graph.getNodes().forEach((node) => {
        if (!node.isVisible()) node.show();
      });
      graph.getEdges().forEach((edge) => {
        if (!edge.isVisible()) edge.show();
      });

      let nodes = [],
        edges = [];
      const processRes = processNodesEdges(graphData.nodes, graphData.edges);

      graph.changeData(processRes);
      // layout.destroy()
      // layout.init()
      // layout.start()
      // layout.instance = new G6.Layout['gForce'](layoutConfig)
      // layout.instance.tick = () => {
      //     graph.refreshPositions()
      //     console.log('tick~')
      // }
      // layout.instance.getMass = (d) => {
      //     const cachePosition = cachePositions[d.id]
      //     if (cachePosition) return 5
      //     return 1
      // }
      // layout.instance.execute()
      // graph.render()
      // graph.fitView()
      console.log(graph, layout, apis);
    };

    const processNodesEdges = (nodes, edges, isNewGraph = false) => {
      if (!nodes || nodes.length === 0) return {};
      const currentNodeMap = {};
      nodes.forEach((node) => {
        if (currentNodeMap[node.id]) {
          console.warn('node exists already!', node.id);
          node.id = `${node.id}${Math.random()}`;
        }
        currentNodeMap[node.id] = node;

        const cachePosition = cachePositions ? cachePositions[node.id] : undefined;
        if (cachePosition) {
          node.x = cachePosition.x;
          node.y = cachePosition.y;
          node.new = false;
        } else {
          node.new = isNewGraph ? false : true;
          if (manipulatePosition && !node.x && !node.y) {
            node.x = manipulatePosition.x + 30 * Math.cos(Math.random() * Math.PI * 2);
            node.y = manipulatePosition.y + 30 * Math.sin(Math.random() * Math.PI * 2);
          }
        }
      });

      return { nodes, edges };
    };

    return <Menu bindType="node" options={options} onChange={handleChange} />;
  };

  return (
    <>
      {graphState.network.nodes.length > 0 && (
        <Graphin data={graphState.network} layout={layoutConfig} ref={graphinRef}>
          <DragNodeWithForce autoPin={false} />
          <ActivateRelations />
          <ContextMenu style={{ width: '80px' }} bindType="node">
            <NodeMenu />
          </ContextMenu>
          <OptionToolbarTwo />
        </Graphin>
      )}
    </>
  );
};

export { ControlPathGraph, ControlledNetworkGraph, ControlNetworkGraph, CapitalNetworkGraph };
